#include "screen.h"
#include "mario.h"

/* define small tile */
enum Tile {
    NONE = 0,
    GREEN,
    ORANGE,
    YELLOW,
    PURPLE,
    BLUE,
    CYAN,
    RED,
    LAST
};

/* 4 bits for type of tile*/
#define TILE_MASK 0x0F

/* use these two values to define colors */
#define A 220
#define B 110

static const RGB TILE_COLORS[NUM_TILES] = {
	[NONE] = {0, 0, 16},
	[GREEN] = {0, A, 0},
	[ORANGE] = {A, B, 0},
	[YELLOW] = {A, A, 0},
	[PURPLE] = {A, 0, A},
	[BLUE] = {0, 0, A},
	[CYAN] = {0, A, A},
	[RED] = {A, 0, 0},
	[LAST] = {B, B, B},
};

/* 7 combination of 4 tiles tetrominos   */
#define NUM_TETROMINOS 7
#define NUM_SHAPES 19
const u16 TETROMINOS[NUM_SHAPES] = {
	/* O, 1 rotation only */
	0x569A,
	/* S, 2 rotations */
	0x2569, 0x459A,
	/* Z */
	0x156A, 0x5689,
	/* I */
	0x159D, 0x4567,
	/* T, 4 rotations */
	0x1569,	0x1456,	0x1459,	0x4569,
	/* L */
	0x456A,	0x1259,	0x0456,	0x1589,
	/* J */
	0x2456,	0x0159,	0x4568,	0x159A
};

/* 4x4 tiles */
#define TTM_SIZE 4

/* TTM state */
struct TTM_STATE {
	i8 board[WORLD_HEIGHT][WORLD_WIDTH]; /* the board */
	u8 curr; /* current tetromino */
	i16 x, y;
	u8 rot;
	bool done, game_over;
	u8 next; /* next tetromino */
	u32 score, lines, level;
	int lines_left;
	u32 frames, steps, frames_since_step; /* control the fall speed */
} state;

#define NUM_LEVELS 30
// from listfist.com/list-of-tetris-levels-by-speed-nes-ntsc-vs-pal
u8 FRAMES_PER_STEP[NUM_LEVELS] = {
	48, 43, 38, 33, 28, 23, 18, 13, 8, 6, 5, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2,
	2, 2, 2, 2, 2, 2, 1
};
u32 LINE_MULTIPLIERS[4] = {
	40, 100, 300, 1200
};

/* calculate which tile on window position (tx, ty) */
void * window_tile(int tx, int ty) {
	int wx = state.x + tx;  // world x
	int wy = state.y + ty;	// world y
	// which tile on (wx, wy)?
	if ( wx<0 || wx>=WORLD_WIDTH || wy<0 || wy>=WORLD_HEIGHT)
		return NONE;
	return (void*)(state.board[wy][wx]);
}

/* location (tx, ty)'s unit is tile, not pixel,
   origin point is the top-left of the window */
_Bool window_render(int tx, int ty) {
	/* tile color */
	enum Tile tile = (enum Tile)window_tile(tx,ty) & TILE_MASK;
	setcolor(TILE_COLORS[tile].r, TILE_COLORS[tile].g, TILE_COLORS[tile].b);
	fillrect(tx * TILE_SIZE + 1, ty * TILE_SIZE + 1, TILE_SIZE - 2, TILE_SIZE - 2);
	return true;
}

/* move window with unit of offset (dx, dy) */
void window_move(int dx, int dy) {
	if(state.x+dx>-10 && state.x+dx<WORLD_WIDTH-WINDOW_WIDTH+10 )
		state.x += dx;
	if(state.y+dy>-10 && state.y+dy<WORLD_HEIGHT-WINDOW_HEIGHT+10 )
		state.y += dy;
}

void window_moveto(int wx, int wy) {
	state.x = wx;
	state.y = wy;
}

/* clear the board */
void world_init() {
	size_t x, y;
	memset(state.board, NONE, WORLD_WIDTH*WORLD_HEIGHT);
	for (y = 0; y < WORLD_HEIGHT; y++) {
		state.board[y][0] = state.board[y][WORLD_WIDTH - 1] = LAST;
	}
	for (x = 0; x < WORLD_WIDTH; x++) {
		state.board[WORLD_HEIGHT - 1][x] = LAST;
	}
}

